package com.swak.rto;

/**
 * 统计 RTO 对象: 不是线程安全
 * 
 * 第 一、二、 三、四 次 ; a = 0.125,越是之前的数据所起的作用越小（指数级下降）
 * sampleRTT1
 * (1 - a) * sampleRTT1 + a * sampleRTT2
 * (1 - a) * 【 (1 - a) * sampleRTT1 + a * sampleRTT2  】  + a * sampleRTT3
 * (1 - a) * 【 (1 - a) * 【  (1 - a) * sampleRTT1 + a * sampleRTT2  】 + a * sampleRTT3 】 + a * sampleRTT4
 * sampleRTT1: (1 - a) * (1 - a) * (1 - a)
 * sampleRTT2: (1 - a) * (1 - a) * a
 * sampleRTT3: (1 - a) * a
 * sampleRTT3: a
 * 
 * 场景：
 * 
 * 1. 消息队列， 生产者端发送数据-确认，超时发送；超时时间的确定；
 * 2. 服务调用， 超时时间的确定；（仔细想一想不适合）
 * 
 * 真正适合的场景： -- 需要超时重传的业务； 
 * 例如消息队列发送队列； tcc 事务补偿超时时间确定；可靠消息补偿超时时间确定；
 */
public class RTO {

	/**
	 * 加权系数
	 */
	private Double a = 0.125d;

	/**
	 * 加权系数
	 */
	private Double b = 0.25d;

	/**
	 * 基于移动平均统计的RTT
	 */
	private Long estimateRTT;

	/**
	 * 基于移动平均统计的 标准差
	 */
	private Long devRTT;

	/**
	 * 当前计算的 RTO 值
	 */
	private Long timeoutInerval;

	/**
	 * 传入当前监测的： RTT
	 * 
	 * @param rtt
	 */
	public RTO calculate(long sampleRTT) {

		/*
		 * 第一次监测
		 */
		if (estimateRTT == null) {
			estimateRTT = sampleRTT;
			devRTT = sampleRTT / 2;
		}

		/*
		 * 后期监测
		 */
		else {

			/*
			 * 计算 estimateRTT; a = 0.125
			 */
			estimateRTT = (long) ((1 - a) * estimateRTT + a * sampleRTT);

			/*
			 * 计算 devRTT ; b = 0.25
			 * 分析同上
			 */
			devRTT = (long) ((1 - b) * devRTT + b * Math.abs(estimateRTT - sampleRTT));
		}

		/*
		 * 当前的 RTO
		 */
		this.timeoutInerval = estimateRTT + 4 * devRTT;

		/*
		 * 返回当前的对象
		 */
		return this;
	}

	/**
	 * 返回计算的 RTO 值 
	 * 
	 * @return
	 */
	public Long getTimeoutInerval() {
		return timeoutInerval;
	}
}
